package com.sunpy.commonlock.mysql;

import com.sunpy.commonlock.dao.MysqlLockMapper;
import com.sunpy.commonlock.entity.CommonLockEntity;
import com.sunpy.commonlock.pub.MysqlLockConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * mysql实现分布式锁
 * @author sunpeiyu
 * @date 2023-04-10
 */
@Component
public class MysqlLockServiceImpl implements IMysqlLockService{

    @Autowired
    private MysqlLockMapper mysqlLockMapper;

    @Autowired
    private MysqlLockConfig config;

    /**
     * 根据lockId释放锁
     * @param lockId
     * @return
     */
    @Override
    public boolean releaseLockByLockId(String lockId) {
        if (StringUtils.isEmpty(lockId)) {
            throw new RuntimeException("lockId不能为空！");
        }

        CommonLockEntity queryEntity = mysqlLockMapper.getLockByLockId(lockId);

        if (Objects.isNull(queryEntity)) {
            throw new RuntimeException("锁不存在！");
        }

        try {
            int i = mysqlLockMapper.deleteLockByLockId(lockId);

            if (i == 1) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }

        return false;
    }

    /**
     * 根据lockName释放锁
     * @param lockName
     * @param author
     * @return
     */
    @Override
    public boolean releaseLockByLockName(String lockName, String author) {
        if (StringUtils.isEmpty(lockName)) {
            throw new RuntimeException("lockName不能为空！");
        }

        if (StringUtils.isEmpty(author)) {
            throw new RuntimeException("author不能为空！");
        }

        CommonLockEntity queryEntity = mysqlLockMapper.getLockByLockName(lockName, author);

        if (Objects.isNull(queryEntity)) {
            throw new RuntimeException("锁不存在！");
        }

        try {
            int i = mysqlLockMapper.deleteLockByLockName(lockName, author);

            if (i == 1) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }

        return false;
    }

    /**
     * 根据lockId，锁超时删除锁
     * @param lockId
     */
    public void deleteTimeoutLockByLockId(String lockId) {
        if (StringUtils.isEmpty(lockId)) {
            throw new RuntimeException("lockId不能为空！");
        }

        LocalDateTime currentDateTime = LocalDateTime.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        int timeout = config.getTimeout();
        String diffNowTime = currentDateTime.minusSeconds(timeout).format(dtf);
        mysqlLockMapper.deleteTimeoutLockByLockId(lockId, diffNowTime);
    }

    /**
     * 根据lockName，锁超时删除锁
     * @param lockName
     * @param author
     */
    public void deleteTimeoutLockByLockName(String lockName, String author) {
        if (StringUtils.isEmpty(lockName)) {
            throw new RuntimeException("lockName不能为空！");
        }

        if (StringUtils.isEmpty(author)) {
            throw new RuntimeException("author不能为空！");
        }

        LocalDateTime currentDateTime = LocalDateTime.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        int timeout = config.getTimeout();
        String diffNowTime = currentDateTime.minusSeconds(timeout).format(dtf);
        mysqlLockMapper.deleteTimeoutLockByLockName(lockName, author, diffNowTime);
    }

    /**
     * 获取非阻塞锁
     * @param commonLockEntity
     * @return
     */
    @Override
    public boolean getUnblockedLock(CommonLockEntity commonLockEntity) {
        if (Objects.isNull(commonLockEntity)) {
            throw new RuntimeException("获取锁的对象不能为空！");
        }

        if (StringUtils.isEmpty(commonLockEntity.getLockName())) {
            throw new RuntimeException("锁的名称不能为空！");
        }

        if (StringUtils.isEmpty(commonLockEntity.getAuthor())) {
            throw new RuntimeException("锁的拥有者不能为空！");
        }

        // 检测处理锁超时
        this.deleteTimeoutLockByLockName(commonLockEntity.getLockName(), commonLockEntity.getAuthor());
        CommonLockEntity queryEntity =
                mysqlLockMapper.getLockByLockName(commonLockEntity.getLockName(), commonLockEntity.getAuthor());

        if (Objects.isNull(queryEntity)) {
            try {
                int i = mysqlLockMapper.insertLock(commonLockEntity);

                if (i == 1) {
                    return true;
                }
            } catch (Exception e) {
                return false;
            }
        }

        // 锁重入，直接返回true
        if (config.isReentry()) {
            return true;
        }

        return false;
    }

    /**
     * 根据lockName续期锁
     * @param lockName
     * @param author
     * @return
     */
    @Override
    public boolean renewLockByLockName(String lockName, String author) {
        CommonLockEntity queryEntity =  mysqlLockMapper.getLockByLockName(lockName, author);
        if (Objects.isNull(queryEntity)) {
            throw new RuntimeException("锁不存在！");
        }

        int retime = config.getRetime();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime createtime = LocalDateTime.parse(queryEntity.getCreatetime(), dtf);
        String renewCreatetime = createtime.plusSeconds(retime).format(dtf);
        int j = mysqlLockMapper.updateLockByLockName(lockName, author, renewCreatetime);
        return j == 1;
    }

    /**
     * 根据lockId续期锁
     * @param lockId
     * @return
     */
    @Override
    public boolean renewLockByLockId(String lockId) {
        CommonLockEntity queryEntity = mysqlLockMapper.getLockByLockId(lockId);

        if (Objects.isNull(queryEntity)) {
            throw new RuntimeException("锁不存在！");
        }

        int retime = config.getRetime();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime createtime = LocalDateTime.parse(queryEntity.getCreatetime(), dtf);
        String renewCreatetime = createtime.plusSeconds(retime).format(dtf);
        int i = mysqlLockMapper.updateLockByLockId(lockId, renewCreatetime);
        return i == 1;
    }
}
